import BinaryReader from "../binary/BinaryReader"
import { ValueType, AnyValueType } from "./ObjTypeDef"

const VT = ValueType
const AVT = AnyValueType

/** 
 * 对象解码
 *  @param beforeStart 开始前的处理
 */
export default function decodeObj<T extends Object>(bytes: Uint8Array, struct: any[]): T {
    let r = BinaryReader.alloc(bytes)
    let obj = deStruct(r, struct)
    r.recy()
    return obj
}

/** 
 *  对象解码(读出结构)
 *  @param readStruct 开始前的处理
 */
export function decodeObjDeal<T extends Object>(bytes: Uint8Array, readStruct?: (r: BinaryReader) => any[]): T {
    let r = BinaryReader.alloc(bytes)
    let obj = deStruct(r, readStruct(r))
    r.recy()
    return obj
}

/** 解码结构 */
function deStruct(r: BinaryReader, struct: any[]) {
    let obj: any = {}
    let sLen = struct.length

    //[读取] >>> 标志位
    //用于判断bit对应字段是否有数据，或者bool的真假
    let flag = []
    let fLen = sLen / 8 >> 0
    for (let i = fLen + 1; i--;) {
        flag.push(r.byte)
    }

    //开始遍历字段 idx为第几个字段
    for (let idx = 0; idx < sLen; idx++) {
        let [field, vt] = struct[idx]

        //检测标志位bit对应字段是否有值
        let has = flag[idx / 8 >> 0] & (1 << idx % 8)
        if (vt <= VT.arr) {
            //======== 解码有类型对象、any类型对象和数组 ========
            let val: any
            //[读取] >>> 值
            switch (vt) {
                case VT.bool:
                    val = has ? true : false
                    break
                case VT.byte:
                    val = has ? r.byte : 0
                    break
                case VT.uint8:
                    val = has ? r.uint8 : 0
                    break
                case VT.uint16:
                    val = has ? r.uint16 : 0
                    break
                case VT.uint32:
                    val = has ? r.uint32 : 0
                    break
                case VT.uint:
                    val = has ? r.uint : 0
                    break
                case VT.int8:
                    val = has ? r.int8 : 0
                    break
                case VT.int16:
                    val = has ? r.int16 : 0
                    break
                case VT.int32:
                    val = has ? r.int32 : 0
                    break
                case VT.int:
                    val = has ? r.int : 0
                    break
                case VT.float:
                    val = has ? r.float : 0
                    break
                case VT.str:
                    val = has ? r.str : ""
                    break
                case VT.struct:
                    val = has ? deStruct(r, struct[idx][2]) : {}
                    break
                case VT.obj:
                    val = has ? deObj(r) : {}
                    break
                case VT.arr:
                    val = has ? deArr(r) : []
                    break
            }
            obj[field] = val
        } else {
            //======== 解码有类型数组 ========
            let arr = []
            if (has) {
                //递归遍历数组维度
                let vecMax = struct[idx][2]
                let fn = function (run: (aLen: number) => any[], vec: number = 1) {
                    //[读取] >>> 数组长度
                    let _aLen = r.uint

                    if (vec++ < vecMax) {
                        let va = []
                        for (let i = _aLen; i--;) {
                            va.push(fn(run, vec))
                        }
                        return va
                    } else {
                        //[读取] >>> 数组长度
                        return run(_aLen)
                    }
                }
                let fn2 = function (val: () => any) {
                    arr = fn(aLen => {
                        let arr = []
                        for (let i = aLen; i--;) {
                            arr.push(val())
                        }
                        return arr
                    })
                }
                //[读取] >>> 值
                switch (vt) {
                    case VT.boolArr:
                        arr = fn(aLen => {
                            let arr = []
                            //[读取] >>> bool标志位 用于判断位对应真假
                            let bFlag = []
                            let bFLen = arr.length / 8 >> 0
                            for (let i = bFLen + 1; i--;) {
                                bFlag.push(r.byte)
                            }
                            for (let aIdx = 0; aIdx < aLen; aIdx++) {
                                arr.push(bFlag[aIdx / 8 >> 0] & (1 << aIdx % 8) ? true : false)
                            }
                            return arr
                        })
                        break
                    case VT.byteArr:
                        fn2(() => r.byte)
                        break
                    case VT.uint8Arr:
                        fn2(() => r.uint8)
                        break
                    case VT.uint16Arr:
                        fn2(() => r.uint16)
                        break
                    case VT.uint32Arr:
                        fn2(() => r.uint32)
                        break
                    case VT.uintArr:
                        fn2(() => r.uint)
                        break
                    case VT.intArr:
                        fn2(() => r.int)
                        break
                    case VT.floatArr:
                        fn2(() => r.float)
                        break
                    case VT.strArr:
                        fn2(() => r.str)
                        break
                    case VT.structArr:
                        let _struct = struct[idx][3]
                        fn2(() => deStruct(r, _struct))
                        break
                }
            }
            obj[field] = arr
        }
    }
    return obj
}

//解码any类型对象值
function deVal(r: BinaryReader) {
    //[读取] >>> 值类型 对象值
    switch (r.byte) {
        case AVT.true:
            return true
        case AVT.false:
            return false
        case AVT.int:
            return r.int
        case AVT.e_int:
            return 0
        case AVT.float:
            return r.float
        case AVT.str:
            return r.str
        case AVT.e_str:
            return ""
        case AVT.obj:
            return deObj(r)
        case AVT.e_obj:
            return {}
        case AVT.arr:
            return deArr(r)
        case AVT.e_obj:
            return []
    }
}

//解码any类型对象
function deObj(r: BinaryReader) {
    let obj: any = {}
    //[读取] >>> 字段数量
    let len = r.uint
    while (len-- > 0) {
        //[读取] >>> 字段名 值
        let field = r.str
        obj[field] = deVal(r)
    }
    return obj
}

//解码any类型数组
function deArr(r: BinaryReader) {
    let arr = []
    //[读取] >>> 数组长度 值
    let len = r.uint
    while (len-- > 0) {
        arr.push(deVal(r))
    }
    return arr
}